﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LibArchivumAeternum;
using System.IO;

namespace ArchivumAeternumCli
{
    class Program
    {
        private class Configuration
        {
            public string ConfigFile { get; set; }
            public List<string> Tasks { get; set; }
            public string LogFile { get; set; }
            public Boolean Quiet { get; set; }
        }

        private static Configuration configuration = new Configuration();

        public class Log : IDisposable
        {
            private FileStream logFile;
            private StreamWriter log;

            public Log(string fileName)
            {
                logFile = File.OpenWrite(configuration.LogFile);
                log = new StreamWriter(logFile);
            }

            public void Dispose()
            {
                if (log != null)
                {
                    log.Dispose();
                    log = null;
                }

                if (logFile != null)
                {
                    logFile.Dispose();
                    logFile = null;
                }
            }

            public void WriteLine(string message = "")
            {
                log.Write(message + "\n");
            }

            public void Write(string message)
            {
                if (logFile != null && log != null)
                {
                    if (message == "\n")
                    {
                        log.Write("\n");
                    }
                    else
                    {
                        log.Write(String.Format("{0}: {1}", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff"), message));
                    }
                }
            }
        }

        static void Main(string[] args)
        {
            int copied = 0;
            int linked = 0;
            int skipped = 0;
            int errors = 0;

            try
            {
                ProcessArguments(args);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error processing the arguments: ", ex.Message);
                Environment.Exit(1);
            }

            using (Log log = new Log(configuration.LogFile))
            {
                LibArchivumAeternum.Configuration Configuration = null;

                try
                {
                    Configuration = ConfigFile.Load(configuration.ConfigFile);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error loading configuration: " + ex.Message);
                    log.Write("Error loading configuration: " + ex.Message);
                    Environment.Exit(2);
                }

                ArchivumAeternum archivumAeternum = new ArchivumAeternum(Configuration);

                archivumAeternum.OnStepStarted += (sender, message) =>
                    {
                        log.Write(message);

                        if (message.StartsWith("Latest backup: "))
                        {
                            log.WriteLine();
                            Console.WriteLine(message);
                        }

                        if (message.StartsWith("Processing directory: "))
                        {
                            log.WriteLine();
                        }
                    };

                archivumAeternum.OnStepFinished += (sender, message) =>
                    {
                        switch (message)
                        {
                            case "copied":
                                Console.Write("c");
                                copied++;
                                break;
                            case "linked":
                                Console.Write(".");
                                linked++;
                                break;
                            case "skipped":
                                Console.Write("!");
                                skipped++;
                                break;
                        }

                        log.WriteLine(" " + message);
                    };

                archivumAeternum.OnStepFailed += (sender, message) =>
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write("X");
                        Console.ForegroundColor = ConsoleColor.Gray;
                        log.WriteLine("ERROR: " + message);
                        errors++;
                    };

                if (configuration.Tasks == null || configuration.Tasks.Count == 0)
                {
                    Console.WriteLine("Task: BATCH");
                    log.WriteLine("Task: BATCH");

                    archivumAeternum.StartBatchBackup();
                    archivumAeternum.WaitForBackup();

                    Console.WriteLine();
                    log.WriteLine();
                }
                else
                {
                    foreach (string task in configuration.Tasks)
                    {
                        Console.WriteLine("Task: {0}", task);
                        log.WriteLine("Task: " + task);

                        archivumAeternum.StartBackup(Configuration.Tasks.Where(t => t.Name == task).FirstOrDefault());
                        archivumAeternum.WaitForBackup();

                        Console.WriteLine();
                        log.WriteLine();
                    }
                }

                Console.WriteLine("\n\nCopied: {0}", copied);
                Console.WriteLine("Linked: {0}", linked);
                Console.WriteLine("Skipped: {0}", skipped);
                Console.WriteLine("Errors: {0}", errors);
            }
        }

        private static void ProcessArguments(string[] args)
        {
            foreach (string argument in args)
            {
                string[] values = argument.Split('=');

                switch (values[0])
                {
                    case "configuration":
                        configuration.ConfigFile = values[1];
                        break;
                    case "logfile":
                        configuration.LogFile = values[1];
                        break;
                    case "quiet":
                        configuration.Quiet = values[1] == "true" ? true : false;
                        break;
                    case "tasks":
                        configuration.Tasks = new List<string>();

                        string[] tasks = values[1].Split(',');

                        for (int x = 0; x < tasks.Length; x++)
                        {
                            configuration.Tasks.Add(tasks[x]);
                        }
                        break;
                }
            }
        }
    }
}
